/* eslint-disable no-console */
import type { IPublicTypeProjectSchema, ResultDir } from '@alilc/lowcode-types';
import createCustomCodeGeneratorProjectBuilder from '../customSolution';
const createCustomBuilder = createCustomCodeGeneratorProjectBuilder;

declare const self: any;

export default function () {
  self.onmessage = (event: any) => {
    const msg = event.data || {};
    if (msg.type === 'run') {
      run(msg);
    }
  };

  self.postMessage({ type: 'ready' });

  interface FlattenFile {
    /**
     * 文件路径
     */
    pathName: string;

    /**
     * 文件内容
     */
    content: string | Buffer;
  }

  function joinPath(...pathParts: string[]): string {
    return pathParts
      .filter((x) => x !== '' && x !== '.')
      .join('/')
      .replace(/\\+/g, '/')
      .replace(/\/+/g, '/');
  }

  function flattenResult(dir: ResultDir, cwd = ''): FlattenFile[] {
    if (!dir.files.length && !dir.dirs.length) {
      return [];
    }

    return [
      ...dir.files.map(
        (file): FlattenFile => ({
          pathName: joinPath(cwd, `${file.name}${file.ext ? `.${file.ext}` : ''}`),
          content: file.content,
        }),
      ),
    ].concat(...dir.dirs.map((subDir) => flattenResult(subDir, joinPath(cwd, subDir.name))));
  }

  async function run(msg: { solution: string; schema: IPublicTypeProjectSchema; flattenResult?: boolean }) {
    try {
      print('begin run...');
      self.postMessage({ type: 'run:begin' });

      const { solution } = msg;
      if (!solution) {
        throw new Error('solution is required');
      }

      const createAppBuilder = createCustomBuilder;
      if (typeof createAppBuilder !== 'function') {
        throw new Error(`solution '${solution}' is invalid`);
      }

      const appBuilder = createAppBuilder();

      print('generating from schema: %o', msg.schema);

      const result = await appBuilder.generateProject(msg.schema);

      print('generated result: %o', result);

      const finalResult = msg.flattenResult
        ? flattenResult(result)
        : result;

      if (msg.flattenResult) {
        print('flatten result: %o', finalResult);
      }

      self.postMessage({
        type: 'run:end',
        result: finalResult,
      });
    } catch (e) {
      printErr(`${e}`);
      self.postMessage({
        type: 'run:error',
        errorMsg: `${(e as Error | null)?.message || e}`,
        errorDetail: `${e}`,
      });
    }
  }

  function print(text: string, ...args: any[]) {
    console.debug(`[code-generator/worker]: ${text}`, ...args);
    self.postMessage({
      type: 'stdout',
      data: text,
      args,
    });
  }

  function printErr(text: string, ...args: any[]) {
    console.debug(`[code-generator/worker]: %c${text}`, 'color:red', ...args);
    self.postMessage({
      type: 'stderr',
      data: text,
      args,
    });
  }
}
